package oop.ex1.filescript;

import java.io.*;
import java.util.*;
import java.io.File;
import oop.ex1.actions.*;
import oop.ex1.filters.*;
import oop.ex1.orders.OrderNameException;
import oop.ex1.orders.OrderType;

/**
 * This class handles all the required methods for File processing.
 * @authors dawn16889 & miron_6
 */
public class MyFileScript {
	
	
	private static final String WHITE_SPACE = " ";
	private static final String FUNCTION_SPLITER = "%";
	private static final String DEFAULT_ORDER = "abs";
	private static File file;
	private static File commandFile;

	/**
	 * constructor
	 * @param comand - the command file
	 * @param files - the source directory
	 */
	public MyFileScript(String comand, String files){
		commandFile = new File(comand);
		file = new File(files);
	}

	/**
	 * this method checks if the given String contains a comment and if so
	 * adds the string to a given ArrayList of Strings
	 * @param com - a String that can either contain a comment or not
	 * @param comments - an ArrayList of comments
	 * @return true if the given String is a comment and false otherwise
	 */
	private static boolean commentCheck(String com, ArrayList<String> comments){
		if (com.startsWith("$")){
			comments.add(com);
			return true;
		}
		return false;		
	}

	/**
	 * this method gets an ArrayList of Strings and prints them in order
	 * @param comments - an ArrayList of comments that should be printed
	 */
	private static void printComments(ArrayList<String> comments){
		for(int i=0; i<comments.size(); i++)
			System.out.println(comments.get(i));
	}

	
	/**
	 * This method conducts a series of command on a given source directory.
	 * There are three kinds of commands: filter, action and order coming in that order.
	 * A command line may also be a comment if it starts with "$" symbol and will be printed.
	 * @throws IOException - for exception regarding to File object methods.
	 * @throws IllegalDateException - thrown by getAction doFilters
	 * @throws FirstCommentException - if the first line on the commandFile is a comment
	 * @throws EmptySubsectionException - if there is no action of filter in one of the blocks
	 * @throws YesNoException -thrown by getAction and doFilters
	 * @throws ActionException - thrown by getAction
	 * @throws FilterNameException - thrown by doFilters
	 * @throws OrderNameException - thrown by treeOrder
	 */
	private static void read() throws IOException, IllegalDateException, FirstCommentException,
								EmptySubsectionException,YesNoException, ActionException,
								FilterNameException, OrderNameException{

		FileReader inFile = new FileReader(commandFile);
		BufferedReader buff = new BufferedReader(inFile);
		ArrayList<TreeBlock> treeBlocks = new ArrayList<TreeBlock>();
		ArrayList<String> tempComments = new ArrayList<String>();
		
		String line;

		// checks if the first line is a comment and acts accordingly
		if (commentCheck(line = buff.readLine(),tempComments))
			throw new FirstCommentException("error");
		while (line != null){
			//initializes all the parameters
			tempComments = new ArrayList<String>();
			ArrayList<String[]> filters = new ArrayList<String[]>();
			TreeSet<File> tempTree= new TreeSet<File>() ;
			ArrayList<Actions> tempAction = new ArrayList<Actions>();
			Comparator<File> order;
			order = OrderType.treeOrder(DEFAULT_ORDER);

			//reads each line and checks if its a comment. if so saves it in an arrayList of Strings. 
			//otherwise, inserts the filters into an ArrayList of strings
			while ((line= buff.readLine())!=null && !(line.equals("ACTION"))){
				if (!commentCheck(line, tempComments)){
					filters.add(line.split(WHITE_SPACE));
				}
			}
			//checks if there is no filters in the current Block and acts accordingly
			if (filters.isEmpty())
				throw new EmptySubsectionException("Error");
			//reads each line and checks if its a comment. if so saves it in an arrayList of Strings. 
			//otherwise, inserts the actions into an ArrayList of actions
			while (!(((line= buff.readLine())== null) || line.equals("ORDER") || line.equals("FILTER"))){
				if (!commentCheck(line,tempComments)){
					String[] action = line.split(FUNCTION_SPLITER);						
					if (action[0].startsWith("print") && action.length>1)
						throw new ActionException();
					if (action[0].equals("copy"))
						tempAction.add(ActionWork.getAction(action[0],action[1],file.getCanonicalPath()));
					else
						tempAction.add(ActionWork.getAction(action[0], action.length>1 ? action[1]:"",""));
				}
			}
			//checks if there is no actions in the current Block and acts accordingly
			if (tempAction.isEmpty())
				throw new EmptySubsectionException("Error");
			//checks if there is an order in the current block and saves it if it exists. 
			//then, saves the rest of the comments in the current Block
			if (line!=null && line.equals("ORDER")){
				while (!((line= buff.readLine())== null || line.equals("FILTER")))
					if (!commentCheck(line,tempComments))
						order = OrderType.treeOrder(line); 
			}
			tempTree = new TreeSet<File>(order);
			FiltersWork.doFilters(filters,file, tempTree);
			TreeBlock tempBlock = new TreeBlock(tempTree,tempAction, tempComments);
			treeBlocks.add(tempBlock);
		}
		buff.close();
		// implementing each actions set on it FIles tree and printing all comments in this block. 
		for (int i = 0 ; i< treeBlocks.size() ; i++){
			ActionWork.doActions(treeBlocks.get(i).getTree(), treeBlocks.get(i).getAction()); 
			printComments(treeBlocks.get(i).getComments());
		}
	}
	
	/**
	 * this method prints an ERROR message and exits the program. 
	 * called after caught exception
	 */
	private static void exceptions(){
		System.err.println("ERROR");
		System.exit(-1);
	}

	
	
	public static void main(String[] args) {
		MyFileScript fileScript = new MyFileScript(args[1], args[0]);
		try{
			fileScript.read();
		}

		catch (IllegalDateException e){
			exceptions();
		}
		catch (FirstCommentException e){
			exceptions();
		}
		catch (EmptySubsectionException e){
			exceptions();
		}
		catch (YesNoException e){
			exceptions();
		}
		catch (ActionException e){
			exceptions();
		}
		catch (CantReadFileException e){
			exceptions();
		}
		catch (FilterNameException e){
			exceptions();
		}
		catch (OrderNameException e){
			exceptions();
		}
		catch (IOException e){
			exceptions();
		}
	}
}